package com.zwl.swagger;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaType;
import com.zwl.swagger.comment.Comment;
import com.zwl.swagger.comment.MethodComment;
import com.zwl.util.FileUtil;
import com.zwl.util.ReflectUtil;
import com.zwl.util.SwaggerSpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 注释收集
 * @author zhangweilin
 * @Description:
 * @date 2021年08月20日 20:59
 */
@Slf4j
public class CommentReader {

	/**
	 * 0表示待执行状态  1表示正在执行
	 */
	private static int state = 0;
	private static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
	private static URL resource = CommentReader.class.getResource("/");
	;
	private static File file = null;
	private static String rootPath = null;
	private static final String configFilePath = "/META-INF/swagger-doc-desc/";

	static void readDoc() {
		log.info("文件编码file.encoding2: " + System.getProperty("file.encoding"));
		if (state == 1 || state == 2) {
			//            log.warning("正在生成文档");
			return;
		}
		state = 1;
		collectorIfHasSrc();
		mergeFromJar();
		state = 2;
	}

	private static void mergeFromJar() {
		log.info("开始合并jar包中的文档");
		try {
			//            Resource[] resources = resourcePatternResolver.getResources("classpath:/META-INF/*.json");
			Resource[] resources = resourcePatternResolver.getResources("classpath*:" + configFilePath + "*.json");
			log.info("文档初始化路径,resources = " + resources);
			for (Resource resource : resources) {
				String commentDescJson = FileUtil.readFromInputStream(resource.getInputStream(), false);
//				log.info("commentDescJson: "+commentDescJson);
				//                System.out.println("commentDescJson = " + commentDescJson);
				Comment comment = JSONObject.parseObject(commentDescJson, Comment.class);
				CommentContainer.COMMENT.getClassCommentMap().putAll(comment.getClassCommentMap());
				CommentContainer.COMMENT.getMethodCommentMap().putAll(comment.getMethodCommentMap());
				CommentContainer.COMMENT.getFieldCommentMap().putAll(comment.getFieldCommentMap());
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	private static void collectorIfHasSrc() {
		Environment environment = SwaggerSpringUtil.getBean(Environment.class);
		String[] activeProfiles = environment.getActiveProfiles();
		log.info("当前环境: " + activeProfiles[0]);
		if ("test".equals(activeProfiles[0])) {
			log.info("测试环境,说明不是本地idea环境下,不扫描源码");
			return;
		}
		List<String> webModuleList;

		long startTime = System.currentTimeMillis();
		log.info("开始扫描源码2");
		final String javaDir=File.separator + "src" + File.separator + "main" + File.separator + "java" ;
		try {
			file = new File(resource.toURI());
//			rootPath = resource.getPath();
			if (file.exists()) {
				String scanParentLevel = environment.getProperty("swagger.scan.parent.level", "3");
				File parentFile = FileUtil.getParentFile(file, Integer.parseInt(scanParentLevel));
				log.info("开始扫描源码3:file:{},parentFile:{}",file,parentFile);
				String[] webModuleArr = parentFile.list();
				webModuleList = Lists.newArrayList(webModuleArr);
				webModuleList.forEach(x->{
					String parentFileAbsolutePath = parentFile.getAbsolutePath();
					if (!parentFileAbsolutePath.endsWith(File.separator)) {
						parentFileAbsolutePath += File.separator;
					}
					parentFileAbsolutePath += x;
					File moduleParentFile = new File(parentFileAbsolutePath);
					log.info("moduleParentFile:"+moduleParentFile.getAbsolutePath());
					if (moduleParentFile.exists()&&moduleParentFile.isDirectory()) {
						List<String> list = FileUtil.getDirPath(moduleParentFile, javaDir);
						list.forEach(e->{
							File srcFile = new File(e);
							if (srcFile.exists()) {
								log.info("扫描到最终代码位置：srcFile:"+srcFile.getAbsolutePath());
								collector(srcFile);
							}
						});
					}
				});


			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
		long endTime = System.currentTimeMillis();
		log.info("扫描源码结束,耗时 "+(endTime-startTime)/1000+"秒");
	}

	static void collector(String baseDir) {
		collector(new File(baseDir));
	}

	static void collector(File file) {
		JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
		try {
			javaProjectBuilder.addSourceTree(file);
		} catch (Exception e) {
			System.err.println("源码读取异常:");
			e.printStackTrace();
//			return;
		}
		Collection<JavaClass> classes = javaProjectBuilder.getClasses();

		for (JavaClass javaClass : classes) {
			String fullClassName = javaClass.toString().replace("class ", "");
			//            System.out.println("fullClassName = " + fullClassName);
			String simpleName = javaClass.getSimpleName();
			//            ClassComment classComment = new ClassComment();

			//类注释
			String classCommentText = javaClass.getComment();
			if (StringUtils.isEmpty(classCommentText)) {
				List<DocletTag> tags = javaClass.getTags();
				if (!CollectionUtils.isEmpty(tags)) {
					for (DocletTag tag : tags) {
						String name = tag.getName();
						String value = tag.getValue();
						if (!StringUtils.isEmpty(name) && name.startsWith("Description")) {
							if (!StringUtils.isEmpty(value)) {
								value = value.replaceAll("\\s.*", "");
							}
							classCommentText = value;
							break;
						}

					}
				}
			}
			if (StringUtils.isEmpty(classCommentText)) {
				classCommentText = simpleName;
			}

			CommentContainer.COMMENT.getClassCommentMap().put(fullClassName, classCommentText);
			//            classComment.setComment(classCommentText);

			// 获得方法列表
			//            Map<String, MethodComment> methodCommentMap = new HashMap<>();
			List<JavaMethod> methods = javaClass.getMethods();
			for (JavaMethod method : methods) {
				String methodName = method.getName();
				//                System.out.println("methodName = " + methodName);

				MethodComment methodComment = new MethodComment();
				String methodCommentText = method.getComment();
				methodComment.setComment(methodCommentText);

				Map<String, String> paramCommentMap = new LinkedHashMap<>();
				List<DocletTag> tagList = method.getTags();
				for (DocletTag docletTag : tagList) {
					String name = docletTag.getName();
					String value = docletTag.getValue();
					String key = value.replaceAll("\\s.*", "");
					value = value.replace(key, "").trim();

					if ("param".equals(name)) {
						paramCommentMap.put(key, value);
					}
				}
				methodComment.setParamCommentMap(paramCommentMap);

				List<JavaType> parameterTypes = method.getParameterTypes();
				StringBuilder methodDesc = new StringBuilder("(");
				StringBuilder methodDesc2 = new StringBuilder("(");
				for (int i = 0; i < parameterTypes.size(); i++) {
					JavaType javaType = parameterTypes.get(i);
					Object name = ReflectUtil.getFieldValue(javaType, "name");
					//                    Object fullName = ReflectUtil.getFieldValue(javaType, "fullName");
					Object fullName = javaType.toString();
					methodDesc.append(name);
					methodDesc2.append(fullName);
					if (i != parameterTypes.size() - 1) {
						methodDesc.append(", ");
						methodDesc2.append(", ");
					}
				}
				methodDesc.append(")");
				methodDesc2.append(")");

				String classCommentKey = fullClassName + "#" + methodName + methodDesc;
				String classCommentKey2 = fullClassName + "#" + methodName + methodDesc2;
//				System.out.println("classCommentKey = " + classCommentKey);
//				System.out.println("classCommentKey2 = " + classCommentKey2);
				CommentContainer.COMMENT.getMethodCommentMap().put(classCommentKey, methodComment);
				CommentContainer.COMMENT.getMethodCommentMap().put(classCommentKey2, methodComment);
			}
			//            classComment.setMethodCommentMap(methodCommentMap);

			//            Map<String, String> fieldsCommentMap = new HashMap<>();
			List<JavaField> fields = javaClass.getFields();
			for (JavaField field : fields) {
				String name = field.getName();
				String comment = field.getComment();
				//                System.out.println("comment = " + comment);
				String fieldsCommentKey = fullClassName + "#" + name;
				//                System.out.println("fieldsCommentKey = " + fieldsCommentKey);
				CommentContainer.COMMENT.getFieldCommentMap().put(fieldsCommentKey, comment);
			}
			//            classComment.setFieldsCommentMap(fieldsCommentMap);
			//汇总,此key待定
			//            classCommentMap.put(className, classComment);
		}
		//        System.out.println("classCommentMap = " + classCommentMap);

		//        System.out.println("CommentContainer.COMMENT = " + CommentContainer.COMMENT);
		String json = JSONObject.toJSONString(CommentContainer.COMMENT);
		//        System.out.println("json = " + json);

		URL resource = CommentReader.class.getClassLoader().getResource("");
		String rootPath = resource.getPath();
		rootPath = rootPath + configFilePath;
		//        System.out.println("rootPath = " + rootPath);
		FileUtil.createDir(rootPath);
		File file1 = file;
		file1 = FileUtil.getParentFile(file1,3);
		//        String absolutePath = file1.getAbsolutePath();
		//        System.out.println("absolutePath = " + absolutePath);
		String projectName = file1.getName();
		//        System.out.println("projectName = " + projectName);
		FileUtil.writeFile(projectName + ".json", rootPath, json);
		System.out.println("文档初始化完毕");

	}

}
